package com.yuandian.customer.perception.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuandian.api.customer_perception.po.SystemAnalysisParams;
import com.yuandian.api.customer_perception.po.SystemCompareTrendParams;
import com.yuandian.api.customer_perception.vo.*;
import com.yuandian.api.management.feign.RemoteAreaService;
import com.yuandian.api.management.feign.RemoteBusinessHallService;
import com.yuandian.api.management.feign.RemoteBusinessService;
import com.yuandian.base.service.ITaskDataService;
import com.yuandian.bpm.common.core.constant.CommonConstants;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.customer.perception.mapper.SystemAnalysisMapper;
import com.yuandian.customer.perception.service.ISystemAnalysisService;
import com.yuandian.enums.ApiResultCodeEnum;
import com.yuandian.enums.TableNameEnum;
import com.yuandian.po.BaseSearch;
import com.yuandian.po.MergeDataConfig;
import com.yuandian.po.MergeField;
import com.yuandian.po.MultipleTableInfo;
import com.yuandian.utils.*;
import com.yuandian.utils.poi.ExcelTitleUtils;
import com.yuandian.utils.poi.ExcelUtil;
import com.yuandian.vo.TrendDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 说明：系统分析service实现
 * @Author yanjun
 * @Date 2021/8/11 13:37
 */
@Slf4j
@Service
public class SystemAnalysisServiceImpl implements ISystemAnalysisService {


    @Autowired
    private SystemAnalysisMapper systemAnalysisMapper;

    @Autowired
    private RemoteAreaService remoteAreaService;
    @Autowired
    private RemoteBusinessHallService remoteBusinessHallService;

    @Autowired
    private RemoteBusinessService remoteBusinessService;

    @Autowired
    private ITaskDataService taskDataService;


    /**
     * 查询系统分析概况
     * @param params 系统分析请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> querySystemAnalysisOverview(SystemAnalysisParams params) {
		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
		params.setMultipleTableInfoList(newMultipleTableInfoList);

        // 查询分析指标
        SystemAnalysisOverviewVo vo = systemAnalysisMapper.querySystemAnalysisOverview(params);
        if (vo == null) { return R.ok(vo); }

        // 查询业务量
        R<List<SearchOptionVo>> listR = remoteBusinessService.queryBusinessBySystemId(params.getSystemId());
        if (listR.getCode() == CommonConstants.FAIL) {
            log.error("远程调用配置系统获取获取业务量数据失败，错误：{}", listR.getMsg());
        }
        List<SearchOptionVo> optionList = listR.getData();
        if (!CollectionUtils.isEmpty(optionList)) {
            vo.setBusinessCount(optionList.size());
        } else {
            vo.setBusinessCount(0);
        }

        // 返回数据
        return R.ok(vo);
    }


    /**
     * 查询系统告警占比
     * @param params 系统分析请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> querySystemAlarmProportion(SystemAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.MYSQL_BUSI_BASE_ALARM_STAT.getName());
		List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
		params.setMultipleTableInfoList(newMultipleTableInfoList);

		// 执行查询
        List<SystemAlarmProportionVo> voList = systemAnalysisMapper.querySystemAlarmProportion(params);
        // 返回数据
        return R.ok(voList);
    }


    /**
     * 查询系统指标趋势
     * @param params 系统分析请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> querySystemIndicatorTrend(SystemAnalysisParams params) {
        // 1、获取表信息集
        MultipleTableInfo info = DynamicTableNameUtil.generalSingleTableNamesFromTimeRange(
                params.getStartTime(),
                params.getEndTime());
        // 2、校验表是否存在，剔除不存在的表
		List<String> tableNameList = Collections.singletonList(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());

        // 3、设置表名、时间范围矫正
        params.setTableNameList(tableNameList);
        params.setStartTime(info.getStartTime());
        params.setEndTime(info.getEndTime());
        // 4、执行查询
        List<SystemIndicatorTrendVo> voList = systemAnalysisMapper.querySystemIndicatorTrend(params);
        // 5、归并数据
        Integer minScale = DynamicTableNameUtil.getMinScaleByTableType(info.getTableType());
        Integer scale = null;
        if (params.getScale() != null) {
            scale = DynamicTableNameUtil.getScaleByMinScaleAndParam(minScale, params.getScale());
        }
        List<MergeField> mergeFieldList = new ArrayList<>();
        params.getAnalysisIndicatorTypes().forEach(type -> {
            switch (type) {
                case VISIT_COUNT:
                    mergeFieldList.add(new MergeField("visitCount"));
                    break;
                case TOTAL_SERVER_RESPONSE_TIME:
                    mergeFieldList.add(new MergeField("totalServerResponseTime"));
                    break;
                case AVG_SERVER_RESPONSE_TIME:
                    mergeFieldList.add(new MergeField("avgServerResponseTime", (map, inx, labelTimeUsecList, currentScale) -> {
                        Double totalServerResponseTime = map.get("totalServerResponseTimeList").get(inx);
                        Double visitCount = map.get("visitCountList").get(inx);
                        return MathUtil.divideKeepNoFormat(totalServerResponseTime, visitCount, 2);
                    }));
                    break;
                case HEALTH_RATE:
                    mergeFieldList.add(new MergeField("healthRate", (map, inx, labelTimeUsecList, currentScale) -> {
                        Double visitCount = map.get("visitCountList").get(inx);
                        Double alarmCount = map.get("alarmCountList").get(inx);
                        return MathUtil.divideKeepNoFormat((visitCount - alarmCount) * 100, visitCount, 2);
                    }));
                    break;
                case COMPLETE_COUNT:
                    mergeFieldList.add(new MergeField("completeCount"));
                    break;
                case FAIL_COUNT:
                    mergeFieldList.add(new MergeField("failCount"));
                    break;
                case ALARM_COUNT:
                    mergeFieldList.add(new MergeField("alarmCount"));
                    break;
                case COMPLETE_FAIL_COUNT:
                    mergeFieldList.add(new MergeField("completeFailCount"));
                    break;
                case COMPLETE_ALARM_COUNT:
                    mergeFieldList.add(new MergeField("completeAlarmCount"));
                    break;
                default:
                    break;
            }
        });
        Map<String, Object> map = MergeDataUtil.mergeData(new MergeDataConfig.Builder(
                SystemIndicatorTrendVo.class,
                voList,
                params.getStartTime(),
                params.getEndTime(),
                mergeFieldList)
                .labelTimeFormatter("MM-dd'\n'HH:mm")
                .scale(scale)
                .build());
        map.put("minScale", minScale);
        // 6、重新构建趋势图结果对象
        TrendDataVo trendDataVo = taskDataService.getTrendObject("KHGZ-详单分钟统计", params.getStartTime(), params.getEndTime(), map);
        // 7、返回数据
        return R.ok(trendDataVo);
    }


    /**
     * 查询系统对比趋势
     * @param params 系统对比趋势请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> querySystemCompareTrend(SystemCompareTrendParams params) {
        SystemCompareTrendVo vo = new SystemCompareTrendVo();
        // 查询每组时间范围的数据，存放在compareMap中
        Map<Integer, List<SystemCompareTrendVo>> compareMap = new HashMap<>();
        List<BaseSearch> timeRangeGroup = params.getTimeRangeGroup();
        if (params.getTimeCycle().equals(1)) {
            // 天
            int count = 0;
            for (int i = 0; i < timeRangeGroup.size(); i++) {
                // 1、设置表名
                BaseSearch timeRange = timeRangeGroup.get(i);
                String tableName = TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName();
                if (StringUtils.isEmpty(tableName)) {
                    compareMap.put((i + 1), new ArrayList<>());
                    count++;
                    continue;
                }

                // 2、查询数据
                params.setTableName(tableName);
                params.setStartTime(timeRange.getStartTime());
                params.setEndTime(timeRange.getEndTime());
                // 增加最新数据时间字段，给数组的每个元素，前端可以取数组的第一个元素，就可以知道最新数据时间
                TrendDataVo trendDataVo = taskDataService.getTrendObject("KHGZ-详单分钟统计", params.getStartTime(), params.getEndTime(), null);
                List<SystemCompareTrendVo> voList = systemAnalysisMapper.querySystemCompareTrend(params);
                voList.forEach(systemCompareTrendVo -> {
                    systemCompareTrendVo.setNewestDataTime(trendDataVo.getTrendEndTime());
                });
                compareMap.put((i + 1), voList);
            }
            if (count >= 3) {
                return R.failed(
                        ApiResultCodeEnum.NO_EXIST_TABLE_DYNAMIC.getCode(),
                        ApiResultCodeEnum.NO_EXIST_TABLE_DYNAMIC.getMsg());
            }
        } else {
            // 周、月
            params.setTableName(TableNameEnum.MYSQL_BUSI_SYS_DETAIL_STAT_M.getName());
            for (int i = 0; i < timeRangeGroup.size(); i++) {
                BaseSearch timeRange = timeRangeGroup.get(i);
                params.setStartTime(timeRange.getStartTime());
                params.setEndTime(timeRange.getEndTime());
                List<SystemCompareTrendVo> voList = systemAnalysisMapper.querySystemCompareTrend(params);
                compareMap.put((i + 1), voList);
            }
        }
        return R.ok(compareMap);
    }

    /**
     * 分页查询系统业务总览
     * @param params 系统分析请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> querySystemBusinessOverview(SystemAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
		params.setMultipleTableInfoList(newMultipleTableInfoList);

		// 设置分页对象，如果不传pageNum或pageSize，相当于不分页
        Page<SystemBusinessOverviewVo> page = null;
        if (params.getPageNum() > 0 && params.getPageSize() > 0) {
            page = new Page<>(params.getPageNum(), params.getPageSize());
        }
        // 执行查询
        List<SystemBusinessOverviewVo> voList = systemAnalysisMapper.querySystemBusinessOverview(params, page);
        // 转换业务数据
        // 返回分页对象
        if (page == null) { return R.ok(new PageDataInfo(voList.size(), voList)); }

        return R.ok(new PageDataInfo(page, voList));
    }


    /**
     * 导出系统业务总览列表
     * @param params 系统分析请求参数
     * @param response 响应上下文
     */
    @Override
    public void exportSystemBusinessOverview(SystemAnalysisParams params, HttpServletResponse response) throws Exception {
        // 1、查询要导出的数据
        params.setPageNum(1);
        params.setPageSize(-1);
        PageDataInfo pageDataInfo = BeanUtils.cast(querySystemBusinessOverview(params).getData());
        List<SystemBusinessOverviewVo> list = new ArrayList<>();
        try {
            list = BeanUtils.cast(pageDataInfo.getData());
        } catch (Exception e) {
            log.error("所选时间表不存在!但表格需要正常导出.");
        }
        // 2、导出Excel
        String title = "业务总览列表";
        List<String> titleParams = new ArrayList<>();
        titleParams.add(title);
        titleParams.add(params.getSystemName());
        if (params.getAreaCode() != null && !"".equals(params.getAreaCode())){
            R<String> nameRes = remoteAreaService.queryAreaName(params.getAreaCode());
            if (nameRes.getCode() == CommonConstants.FAIL){
                log.error("远程调用配置系统获取区域名称失败,错误：{}",nameRes.getMsg());
            }
            titleParams.add(nameRes.getData());
        }
        String formTitleName = ExcelTitleUtils.formTitleName(titleParams,params.getStartTime(),params.getEndTime());
        int index = 1;
        for (SystemBusinessOverviewVo systemBusinessOverviewVo : list) {
            systemBusinessOverviewVo.setId(index++);
            systemBusinessOverviewVo.setHealthRate(systemBusinessOverviewVo.getHealthRate()+"%");
            systemBusinessOverviewVo.setSuccessRate(systemBusinessOverviewVo.getSuccessRate()+"%");
            systemBusinessOverviewVo.setAvgVisitTime(String.format("%.2f",Double.valueOf(systemBusinessOverviewVo.getAvgVisitTime())/1000000)+"秒");
            systemBusinessOverviewVo.setAvgServerResponseTime(String.format("%.2f",Double.valueOf(systemBusinessOverviewVo.getAvgServerResponseTime())/1000000)+"秒");
        }
         // 表单大标题
        List<List<String>> headList = new ArrayList<>();
        List<String> titleList = Arrays.asList("序号", "业务名称", "访问量","受理量", "失败访问量", "告警访问量", "平均办理时长", "平均响应时长", "成功率", "健康度");
        titleList.forEach(s -> {
            List<String> childHeadList = new ArrayList<>();
            childHeadList.add(formTitleName);
            childHeadList.add(s);
            headList.add(childHeadList);
        });
        ExcelUtil.writeExcel(SystemBusinessOverviewVo.class, "", "业务总览列表", list,headList,response);
    }


    /**
     * 查询业务指标TOPN
     * @param params 系统分析请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryBusinessIndicatorTopN(SystemAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
		params.setMultipleTableInfoList(newMultipleTableInfoList);

		switch (params.getAnalysisIndicatorType()) {
            case HEALTH_RATE:
                params.setOrderByColumn("healthRate");
                break;
            case VISIT_COUNT:
                params.setOrderByColumn("visitCount");
                break;
            case AVG_SERVER_RESPONSE_TIME:
                params.setOrderByColumn("avgServerResponseTime");
                break;
            case FAIL_COUNT:
                params.setOrderByColumn("failCount");
                break;
        }

        // 执行查询
        List<BusinessIndicatorTopNVo> voList = systemAnalysisMapper.queryBusinessIndicatorTopN(params);

        // 返回数据
        return R.ok(voList);
    }


    /**
     * 分页查询系统操作员总览
     * @param params 系统分析请求参数
     * @return 通用分页对象
     */
    @Override
    public R<Object> querySystemOperatorOverview(SystemAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
		params.setMultipleTableInfoList(newMultipleTableInfoList);

		// 设置分页对象，如果不传pageNum或pageSize，相当于不分页
        Page<SystemOperatorOverviewVo> page = null;
        if (params.getPageNum() > 0 && params.getPageSize() > 0) {
            page = new Page<>(params.getPageNum(), params.getPageSize());
        }
        // 执行查询
        List<SystemOperatorOverviewVo> voList = systemAnalysisMapper.querySystemOperatorOverview(params, page);

		// 转换业务数据
        // 返回分页对象
        if (page == null) { return R.ok(new PageDataInfo(voList.size(), voList)); }

        return R.ok(new PageDataInfo(page, voList));
    }


    /**
     * 导出系统操作员总览列表
     * @param params 系统分析请求参数
     * @param response 响应上下文
     */
    @Override
    public void exportSystemOperatorOverview(SystemAnalysisParams params, HttpServletResponse response) throws Exception {
        // 1、查询要导出的数据
        params.setPageNum(1);
        params.setPageSize(-1);
        PageDataInfo pageDataInfo = BeanUtils.cast(querySystemOperatorOverview(params).getData());
        List<SystemOperatorOverviewVo> list = new ArrayList<>();
        try {
            list = BeanUtils.cast(pageDataInfo.getData());
        } catch (Exception e) {
            log.error("所选时间表不存在!但表格需要正常导出.");
        }
        // 2、导出Excel
        String title = "操作员总览列表";
        String fileName = title + System.currentTimeMillis();
        List<String> titleParams = new ArrayList<>();
        titleParams.add(title);
        titleParams.add(params.getSystemName());
        if (params.getAreaCode() != null && !"".equals(params.getAreaCode())){
            R<String> nameRes = remoteAreaService.queryAreaName(params.getAreaCode());
            if (nameRes.getCode() == CommonConstants.FAIL){
                log.error("远程调用配置系统获取区域名称失败,错误：{}",nameRes.getMsg());
            }
            titleParams.add(nameRes.getData());
        }
        if (params.getBusinessHallId() != null && params.getBusinessHallId() != ""){

            R<String> nameRes = remoteBusinessHallService.queryBusinessHallNameById(params.getBusinessHallId());
            if (nameRes.getCode() == CommonConstants.FAIL){
                log.error("远程调用配置系统获取营业厅名称失败,错误：{}",nameRes.getMsg());
            }
            titleParams.add(nameRes.getData());
        }
        String formTitleName = ExcelTitleUtils.formTitleName(titleParams,params.getStartTime(),params.getEndTime());
        int index = 1;
        for (SystemOperatorOverviewVo vo : list) {
            vo.setId(index++);
            vo.setSuccessRate(vo.getSuccessRate()+"%");
            vo.setAvgVisitTime(String.format("%.2f",Double.valueOf(vo.getAvgVisitTime())/1000000)+"秒");
            //处理数据,分情况回填未知
            if (vo.getBusinessHallId() == null || vo.getBusinessHallId().equals("")) {
                vo.setBusinessHallId("-");
            }
            if (vo.getBusinessHallName() == null || vo.getBusinessHallName().equals("")) {
                if (vo.getBusinessHallId() == "-") {
                    vo.setBusinessHallName("-");
                } else {
                    vo.setBusinessHallName("未知");
                }
            }
            if (vo.getOperatorId() == null || vo.getOperatorId().equals("")) {
                vo.setOperatorId("-");
            }
            if (vo.getOperatorName() == null || vo.getOperatorName().equals("")) {
                if (vo.getOperatorId() == "-") {
                    vo.setOperatorName("-");
                } else {
                    vo.setOperatorName("未知");
                }
            }
        }
        // 表单大标题
        List<List<String>> headList = new ArrayList<>();
        List<String> titleList = Arrays.asList("序号","操作员ID","姓名",params.getOfficeName()+"ID",params.getOfficeName()+"名称", "业务使用数量", "访问量", "受理量", "告警访问量", "失败访问量", "平均办理时长","成功率");
        titleList.forEach(s -> {
            List<String> childHeadList = new ArrayList<>();
            childHeadList.add(formTitleName);
            childHeadList.add(s);
            headList.add(childHeadList);
        });
        ExcelUtil.writeExcel(SystemOperatorOverviewVo.class, fileName, title, list,headList, response);
    }


    /**
     * 查询操作员业务办理量TOPN
     * @param params 系统分析请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryOperatorCompleteTopN(SystemAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
		params.setMultipleTableInfoList(newMultipleTableInfoList);

		// 执行查询
        List<OperatorCompleteTopNVo> voList = systemAnalysisMapper.queryOperatorCompleteTopN(params);

		// 返回数据
        return R.ok(voList);
    }

    /**
     * 查询营业员业务办理失败分布
     * @param params 系统分析请求参数
     * @return 通用返回对象
     */
    
    @Override
    public R<Object> queryOperatorFailBusiness(SystemAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.KHGZ_BUSI_SYS_DETAIL_STAT.getName());
		List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
		params.setMultipleTableInfoList(newMultipleTableInfoList);


		// 4、执行查询
        List<OperatorFailBusinessVo> voList = systemAnalysisMapper.queryOperatorFailBusiness(params);
        // 5、设置前五和其他
        if (!CollectionUtils.isEmpty(voList) && voList.size() > 5) {
            Integer otherFailCount = 0;
            for (int i = 5; i < voList.size(); i++) {
                otherFailCount += voList.get(i).getFailCount();
            }
            OperatorFailBusinessVo vo = new OperatorFailBusinessVo();
            vo.setBusinessCode("other");
            vo.setBusinessName("其他");
            vo.setFailCount(otherFailCount);
            voList.add(5, vo);
            return R.ok(voList.subList(0, 6));
        }
        // 6、返回数据
        return R.ok(voList);
    }

    /**
     * 查询营业员办理业务告警类型分布
     * @param params 系统分析请求参数
     * @return 通用返回对象
     */
    @Override
    public R<Object> queryOperatorBusinessAlarm(SystemAnalysisParams params) {

		// 获取表信息集
		MultipleTableInfo info = new MultipleTableInfo();
		info.setTableName(TableNameEnum.MYSQL_BUSI_BASE_ALARM_STAT.getName());
		List<MultipleTableInfo> newMultipleTableInfoList = Collections.singletonList(info);

		// 设置表信息集，默认排序
		params.setMultipleTableInfoList(newMultipleTableInfoList);

		// 执行查询
        List<OperatorBusinessAlarmVo> voList = systemAnalysisMapper.queryOperatorBusinessAlarm(params);

		// 返回数据
        return R.ok(voList);
    }
}
